package work_space;

import protocol.CommandParser;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class Worker extends Thread {
    private final Socket socket;

    private PrintWriter out;

    private BufferedReader in;

    private String clientName;

    // init socket
    public Worker(Socket socket) throws IOException {
        this.socket = socket;
        this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        this.out = new PrintWriter(socket.getOutputStream(), true);
    }

    @Override
    public void run() {
        try {
            // require client name
            this.clientName = in.readLine();
            if (clientName == null || clientName.trim().isEmpty()) {
                clientName = "Anonymous_" + System.currentTimeMillis();
            }

            WorkSpaceFactory.clientMap.put(clientName, this);
            System.out.println("👋 " + clientName + " joined the caffee");

            out.println(
                    "Hello " + clientName + "! You can now place orders. Commands: 'order X tea/coffee', 'order status', 'collect', 'exit'");
            // 处理客户端命令
            while (true) {
                String originalCommand = in.readLine();
                processCommand(originalCommand);
            }
        } catch (IOException e) {
            System.out.println("⚠️ " + clientName + " disconnected unexpectedly");
        } finally {
            cleanup();
        }
    }

    private void processCommand(String originalCommand) {
        try {
            String command = originalCommand.trim().toLowerCase();

            if (command.startsWith("order")) {
                if (command.equals("order status")) {
                    sendOrderStatus();
                } else {
                    new Thread(() -> processOrder(command)).start();
                }
            } else if (command.equals("collect")) {
                processCollection();
            } else if (command.equals("exit")) {
                out.println("Goodbye " + clientName + "! Thanks for visiting Virtual Caffee!");
                // 移除该客户端
                WorkSpaceFactory.clientMap.remove(clientName);
                throw new IOException("Client exited normally");
            } else {
                out.println(
                        "❌ Unknown command. Available commands: 'order X tea/coffee', 'order status', 'collect', 'exit'");
            }
        } catch (Exception e) {
            out.println("❌ Error processing command: " + e.getMessage());
        }
    }


    private static final Semaphore coffeeSem = new Semaphore(1);

    public static final Semaphore teaSem = new Semaphore(1);

    private void processOrder(String orderCommand) {
        try {
            // 解析订单逻辑 parsedOrder 1 tea / parsedOrder 1 teas and 2 coffees
            Order parsedOrder = CommandParser.parseOrder(orderCommand, clientName);
            if (parsedOrder.getTotalItems() <= 0L) {
                return;
            }
            if (WorkSpaceFactory.orderMap.containsKey(clientName)) {
                // 订单追加
                Order originalOrder = WorkSpaceFactory.orderMap.get(clientName);
                originalOrder.addOrder(parsedOrder);
                if (originalOrder.getOrderStatus().equals(OrderStatus.FINISHED)) {
                    originalOrder.setOrderStatus(OrderStatus.PROCESSING);
                }
            } else {
                // 将订单加入全局map中,方便查找订单
                WorkSpaceFactory.orderMap.put(clientName, parsedOrder);
                // 将订单加入等待区
                Order originalOrder = WorkSpaceFactory.orderMap.get(clientName);
                WorkSpaceFactory.waitingArea.put(clientName, originalOrder);
                // 设置订单状态
                originalOrder.setOrderStatus(OrderStatus.WAITING);
            }
            Order originalOrder = WorkSpaceFactory.orderMap.get(clientName);
            // 向用户发送订单信息
            sendOrderStatus();
            // 开启线程做订单,从等待区中取出订单
            List<CompletableFuture<Void>> futures = new ArrayList<>();
            if (parsedOrder.hasCoffee()) {
                futures.add(brewCoffee(originalOrder));
            }
            if (parsedOrder.hasTea()) {
                futures.add(brewTea(originalOrder));
            }

            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenRunAsync(() -> {
                boolean isFinished = originalOrder.tryFinish();
                if (isFinished) {
                    // 做好了,从制作区中移除
                    WorkSpaceFactory.brewingArea.remove(clientName);
                    // 做好了,放到托盘区
                    WorkSpaceFactory.trayArea.put(clientName, originalOrder);
                    sendOrderStatus();
                }
            });
        } catch (Exception e) {
            out.println("❌ Invalid order format. Use: 'order X tea' or 'order X coffee'");
        }
    }

    private CompletableFuture<Void> brewCoffee(Order originalOrder) {
        return CompletableFuture.runAsync(() -> {
            try {
                coffeeSem.acquire();
                List<Drink> coffeeList = originalOrder
                        .getDrinkList()
                        .stream()
                        .filter(drink -> drink.getDrinkType().equals(DrinkType.COFFEE) && drink
                                .getStatus()
                                .equals(DrinkStatus.WAITING))
                        .toList();
                // 收集所有咖啡制作的Future
                List<CompletableFuture<Void>> coffeeFutures = new ArrayList<>();
                for (int i = 0; i < coffeeList.size(); i++) {
                    final int index = i;
                    Drink drink = coffeeList.get(i);
                    CompletableFuture<Void> coffeeFuture = CompletableFuture.runAsync(() -> {
                        try {
                            // 加锁
                            WorkSpaceFactory.caffeeBrewingSemaphore.acquire();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        if (index == 0) {
                            // 将订单从等待区移除
                            WorkSpaceFactory.waitingArea.remove(clientName);
                            // 将订单加入制作区
                            WorkSpaceFactory.brewingArea.put(clientName, originalOrder);
                            // 设置订单状态为正在处理中
                            originalOrder.setOrderStatus(OrderStatus.PROCESSING);
                            // 向用户发送订单正在处理的信息
                            sendOrderStatus();
                        }
                        try {
                            // 状态推进
                            drink.nextStatus();
                            // 模拟做咖啡
                            try {
                                sendOrderStatus();
                                Thread.sleep(WorkSpaceFactory.COFFEE_BREWING_TIME.toMillis());
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                            // 做好了
                            drink.nextStatus();
                            sendOrderStatus();
                        } finally {
                            // 释放锁
                            WorkSpaceFactory.caffeeBrewingSemaphore.release();
                        }
                    });
                    coffeeFutures.add(coffeeFuture);
                }
                // 等待所有咖啡制作完成
                CompletableFuture.allOf(coffeeFutures.toArray(new CompletableFuture[0])).join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                // 最后释放制作咖啡的锁
                coffeeSem.release();
            }
        });
    }

    private CompletableFuture<Void> brewTea(Order originalOrder) {
        return CompletableFuture.runAsync(() -> {
            try {
                teaSem.acquire();
                List<Drink> teaList = originalOrder
                        .getDrinkList()
                        .stream()
                        .filter(drink -> drink.getDrinkType().equals(DrinkType.TEA) && drink
                                .getStatus()
                                .equals(DrinkStatus.WAITING))
                        .toList();
                // 收集所有制作tea的Future
                List<CompletableFuture<Void>> teaFutures = new ArrayList<>();
                for (int i = 0; i < teaList.size(); i++) {
                    final int index = i;
                    Drink drink = teaList.get(i);
                    CompletableFuture<Void> teaFuture = CompletableFuture.runAsync(() -> {
                        try {
                            // 加锁
                            WorkSpaceFactory.teaBrewingSemaphore.acquire();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        if (index == 0) {
                            // 将订单从等待区移除
                            WorkSpaceFactory.waitingArea.remove(clientName);
                            // 将订单加入制作区
                            WorkSpaceFactory.brewingArea.put(clientName, originalOrder);
                            // 设置订单状态为正在处理中
                            originalOrder.setOrderStatus(OrderStatus.PROCESSING);
                            // 向用户发送订单正在处理的信息
                            sendOrderStatus();
                        }
                        try {
                            // 状态推进
                            drink.nextStatus();
                            // 模拟做tea
                            try {
                                sendOrderStatus();
                                Thread.sleep(WorkSpaceFactory.TEA_BREWING_TIME.toMillis());
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                            // 做好了
                            drink.nextStatus();
                            sendOrderStatus();
                        } finally {
                            // 释放锁
                            WorkSpaceFactory.teaBrewingSemaphore.release();
                        }
                    });
                    teaFutures.add(teaFuture);
                }
                // 等待所有tea制作完成
                CompletableFuture.allOf(teaFutures.toArray(new CompletableFuture[0])).join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                // 最后释放制作tea的锁
                teaSem.release();
            }
        });
    }

    private void sendOrderStatus() {
        Order order = WorkSpaceFactory.orderMap.get(clientName);
        if (order == null) {
            out.println("We couldn't find your order. Please place an order");
            return;
        }
        out.println(order);
    }

    private void processCollection() {
        // 处理取餐逻辑
        // 托盘区有这笔订单,并且这笔订单是完成状态
        if (WorkSpaceFactory.trayArea.containsKey(clientName) && WorkSpaceFactory.trayArea.get(clientName).isFinish()) {
            out.println("✅ Order collected! Enjoy your drinks " + clientName + "!");
            WorkSpaceFactory.trayArea.remove(clientName);
            WorkSpaceFactory.waitingArea.remove(clientName);
            WorkSpaceFactory.orderMap.remove(clientName);
        } else {
            out.println("❌ No completed order available for collection");
        }
    }

    private void cleanup() {
        try {
            // 清理客户端资源
            if (clientName != null) {
                WorkSpaceFactory.clientMap.remove(clientName);
                WorkSpaceFactory.waitingArea.remove(clientName);
                // 清理其他区域中的项目
                System.out.println("👋 " + clientName + " left the caffee");
            }
            if (socket != null && !socket.isClosed()) {
                socket.close();
            }
        } catch (IOException e) {
            System.err.println("Error cleaning up client: " + e.getMessage());
        }
    }

    public void sendMessage(String message) {
        if (out != null) {
            out.println(message);
        }
    }
}
